#include "blog.h"

#define ID_START (128)
#define TOPIC_DESC_ID (1)

#define HEADER_SIZE (sizeof(uint8_t))
#define ID_SIZE (sizeof(uint16_t))
#define PAYLOAD_LEN_SIZE (sizeof(uint16_t))
#define CRC_SIZE (sizeof(uint8_t))
#define TAILER_SIZE (sizeof(uint8_t))
#define PAD_SIZE (HEADER_SIZE + ID_SIZE + PAYLOAD_LEN_SIZE + CRC_SIZE + TAILER_SIZE)

#define MAGIC_HEADER (0xaa)
#define MAGIC_TAILER (0x55)

static blog_cfg_t s_cfg;
static s_id = 0;

static uint8_t crc8(void *data, uint8_t init, uint32_t data_size)
{
    return 0;
}

static inline void flock(void)
{
    s_cfg.f_lock();
}

static inline void funlock(void)
{
    s_cfg.f_unlock();
}

static inline void qlock(void)
{
    s_cfg.q_lock();
}

static inline int write(void *data, uint32_t size)
{
    return s_cfg.write(data, size);
}

static inline void qunlock(void)
{
    s_cfg.q_unlock();
}

static inline uint16_t alloc_id(void)
{
    uint16_t res;
    res = ID_START + s_id;
    s_id++;
    return res;
}

int blog_init(blog_cfg_t *cfg)
{
    s_cfg = *cfg;
}

int blog_log_format(uint16_t id, void *data_in, void *data_out, uint16_t datain_size, uint16_t dataout_size)
{
    int res;
    uint8_t *p_out = data_out;
    uint8_t crc = 0;
    if ((datain_size + PAD_SIZE) > dataout_size)
    {
        res = -1;
    }
    else
    {
        *p_out = MAGIC_HEADER;
        p_out += HEADER_SIZE;
        memcpy(p_out, &id, sizeof(uint16_t));
        p_out += ID_SIZE;
        memcpy(p_out, data_in, datain_size);
        p_out += datain_size;
        *p_out = crc8(data_in, 0, datain_size);
        p_out += CRC_SIZE;
        *p_out = MAGIC_TAILER;
        p_out += TAILER_SIZE;
        res = p_out - ((uint8_t *)data_out);
    }
    return res;
}

int blog_add_topic_fix_id(uint16_t id, const char *topic_desc)
{
    uint8_t header = MAGIC_TAILER;
    uint8_t tailer = MAGIC_TAILER;
    uint8_t crc;
    uint16_t msg_id = TOPIC_DESC_ID;
    uint16_t payload_len;
    int res;
    payload_len = strlen(topic_desc);
    crc = crc8(&id, 0, sizeof(id));
    crc = crc8(topic_desc, crc, payload_len);
    payload_len = payload_len + 2;
    flock();
    if ((write(&header, sizeof(header)) > 0) &&
        (write(&msg_id, sizeof(msg_id)) > 0) &&
        (write(&payload_len, sizeof(payload_len)) > 0) &&
        (write(&id, sizeof(id)) > 0) &&
        (write(topic_desc, payload_len - 2) > 0) &&
        (write(&crc, sizeof(crc)) > 0) &&
        (write(&tailer, sizeof(tailer)) > 0))
    {
        res = 0;
    }
    else
    {
        res = -1;
    }
    funlock();
    return res;
}
int blog_add_topic(const char *topic_desc)
{
    uint16_t id;
    id = alloc_id();
    return blog_add_topic_fix_id(id, topic_desc);
}

int blog_write_log(uint16_t id, void *data, uint16_t data_size)
{
    uint8_t header = MAGIC_HEADER;
    uint8_t tailer = MAGIC_TAILER;
    uint8_t crc = 0;
    int res;
    crc = crc8(&data, crc, data_size);
    flock();
    if (write(&header, sizeof(header)) > 0 &&
        write(&id, sizeof(id)) > 0 &&
        write(&data_size, sizeof(data_size)) > 0 &&
        write(data, data_size) > 0 &&
        write(&crc, sizeof(crc)) > 0 &&
        write(&tailer, sizeof(tailer)))
    {
        res = 0;
    }
    else
    {
        res = -1;
    }
    funlock();
    return res;
}

int blog_queue_log(uint16_t id, void *data, uint16_t data_size)
{
    qlock();
    qunlock();
    return -1;
}
